iT邦幫忙

2024 iThome 鐵人賽

DAY 27
0

練習完文字效果後我打算測試導入模型。
事不宜遲,借一下自己快兩年前用Blender練習捏的動漫風人頭。
一開始導入只有半張臉,趕快apply鏡像修改器,尷尬。

說到3D模型的檔案格式,如果逛過Sketchfab,大概會知道有fbx, obj云云。而這兩者分別適用動態和靜態模型。不過相較於它們,其實GLTF和GLB更適合網路環境。前者更是採用json格式。

熟悉的Poimandres再次佛心來著,開發者Sara Vieira直接做了個GLTF轉換器
把模型丟上去,無痛產出可用程式碼,直接拿來改就行。
光預設就給模型猶如旋轉地台的展示空間,感人。
後來看到別的案例,不只GLTF,GLB也可以拿來轉換喔。

進入實作後,我想提升模型的自轉速度。
這裡不是用speed,而是用autoRotateSpeed={8}去改數值。
調鏡頭焦距則是用adjustCamera,值越大就zoom越遠。

到這有點太容易了,當然要挑戰更多。來模擬相機顫抖吧。

等等,這聽起來不是Blender, AE或UE才做得到嗎?
但drei的<CameraShake />就是這麼優雅。

不過我還想要讓模型持續旋轉,但直接搭配不用動腦的autoRate會使整個模型轉出鏡頭外。因為整個stage在公轉。
於是沿用useRef + useFrame的旋轉手法。

然而有個似乎無傷大雅,卻讓人渾身不對勁的問題是:點進網頁後的剛開始,整個畫面會抖一下。
<CameraShake />也包在suspense裡解決狀況後,又用background-image覆蓋上一層代表相機畫面的svg。心中暗叫:很有感覺。

再來可以做什麼呢?我想還原模型的材質。
本以為依靠glb會很順利,結果沒效還變灰階。
加上寫這段code的那晚,還遇到codesandbox出bug。一整個精神緊張。

所幸最終發現是Blender Node能支援匯出的東西很少。只好試一下烘焙貼圖。
別忘了先unwrap一波,配合image texture即可熱騰騰地產出。
據官方指南記載,在Node有用到Bump的話,插值法選cubic比較好。雖然我是看不太出差別啦……還是先依樣bake。

大概凌晨一點半左右,codesandbox也恢復了。好在模型終於展現應有的質感。

Edit R3F2

//App.js
import { Suspense, useRef } from "react";
import { Canvas } from "@react-three/fiber";
import { CameraShake, Stage } from "@react-three/drei";
import { Model } from "./Model";

export default function Viewer() {
  const ref = useRef();
  return (
    <Canvas shadows dpr={[1, 2]} camera={{ fov: 50 }}>
      <Suspense fallback={null}>
        <Stage
          controls={ref}
          preset="rembrandt"
          intensity={1}
          environment="city"
          adjustCamera={1.5}
        >
          false
          <Model />
          false
        </Stage>
        <CameraShake
          maxYaw={(Math.random() - 0.5) / 2}
          maxPitch={(Math.random() - 0.5) / 2}
          maxRoll={(Math.random() - 0.5) / 2}
          yawFrequency={0.1}
          pitchFrequency={0.1}
          rollFrequency={0.1}
          intensity={1}
          decayRate={0.65}
        />
      </Suspense>
    </Canvas>
  );
}
//Model.js
import React, { useRef } from "react";
import { useFrame } from "@react-three/fiber";
import { useGLTF } from "@react-three/drei";

export function Model(props) {
  const ref = useRef();
  useFrame(() => {
    ref.current.rotation.y += 0.03;
  });

  const { nodes, materials } = useGLTF("./face.glb");
  return (
    <group {...props} dispose={null} ref={ref}>
      <mesh
        castShadow
        receiveShadow
        geometry={nodes.Model.geometry}
        material={materials.Material}
      />
    </group>
  );
}

useGLTF.preload("./face.glb");

上一篇
【Day26】R3F 2
下一篇
【Day28】React Leaflet 1
系列文
【現在學React還來得及嗎?】30天Takeaway分享30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言